package com.sinodata.bsm.cicp.collector.oracle;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.cicp.util.CollectorUtil;
import com.sinodata.bsm.cicp.util.CommandReader;
import com.sinodata.bsm.cicp.util.FileAttribute;
import com.sinodata.bsm.cicp.util.ProtocolParameterUtil;
import com.sinodata.bsm.common.utils.FileUtil;
import com.sinodata.bsm.common.vo.ProtocolParameter;
import com.sinodata.bsm.common.vo.ResPropertyValue;

/**
 * 每个ora日志文件监控需要一个配置文件，在配置文件中指定每种日志的错误级别
 * @author tangli
 * 
 */
public class SystemLog extends Collector {
    private final static String EXTCONFIGPATH = "extconfig/";
    private static Logger logger = Logger.getLogger(SystemLog.class);
    private final static String ERRFLAG = "ORA-";
    private final ORALogFilter filter = new ORALogFilter();

    public SystemLog() {

    }

    @Override
    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        String filePath = this.paramMap.get("FilePath");
        String fileName = this.paramMap.get("FileName");
        String fullFileName = getFullFileName(filePath, fileName);
        String attr2 = this.paramMap.get("FilterCode");
        if (attr2 != null && !attr2.trim().equals("")) {
            String fileName2 = EXTCONFIGPATH + attr2.trim();
            this.filter.init(fileName2);
        }
        fullFileName = fullFileName.trim().replace('\\', '/');
        String errflag = this.paramMap.get("FilterCondition");
        if (errflag == null || errflag.equals("")) {
            errflag = ERRFLAG;
        }
        String tmpFileName = getTmpFileName(fullFileName, errflag, ip);
        FileAttribute lastAttribute = (FileAttribute) FileUtil.readObjFromFile(tmpFileName);
        ProtocolParameter protocolParameter = ProtocolParameterUtil.getHostValue(ip);
        String filterDir = protocolParameter.getUrl();
        FileAttribute currentAttribute;
        try {
            currentAttribute = CollectorUtil.getNewestRemoteFileByPattern(filePath, filterDir, fileName, ip);
        } catch (Exception e1) {
            logger.error("failed to collector oracle log file");
            return null;
        }
        if (currentAttribute == null) {
            return null;
        }
        List<ResPropertyValue> list = null;
        if (lastAttribute != null) {
            if (currentAttribute.size > lastAttribute.size) {
                long position = lastAttribute.size;
                list = readFile(fullFileName, position, errflag, ip);
            } else if (currentAttribute.size < lastAttribute.size) {
                list = readFile(fullFileName, 0, errflag, ip);
            } else {
                list = new ArrayList<ResPropertyValue>();
                String[] propMetas = getPropMeta();
                ResPropertyValue propertyValueX = new ResPropertyValue();
                ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];
                propValues[0] = ResPropertyValue.createPropValue(" ", propMetas[0]);
                propValues[1] = ResPropertyValue.createPropValue(" ", propMetas[1]);
                propertyValueX.setValues(propValues);
                list.add(propertyValueX);
            }
        }
        // 记录文件位置
        if (lastAttribute == null || !lastAttribute.equals(currentAttribute)) {
            try {
                FileUtil.forceWriteObjToFile(tmpFileName, currentAttribute, false);
            } catch (Exception e) {
                logger.error("", e);
            }
        }
        return list;
    }

    private String getTmpFileName(String fileName, String errFlag, String ip) {
        String path = "tmp/";
        StringBuffer buffer = new StringBuffer();
        buffer.append(ip).append("_").append(fileName).append("_").append(errFlag);
        return path + FileUtil.validateFileName(buffer.toString());
    }

    /**
     * 从文件的某个位置开始读，直至文件结束
     * 
     * @param fileName
     * @param readStart
     * @param ip
     * @return
     */
    private List<ResPropertyValue> readFile(String fullFileName, long readStart, String filterPattern, String ip) {

        BufferedReader reader = null;
        String cmd = "filter -f " + fullFileName + " -s " + readStart;
        if (filterPattern != null) {
            cmd = cmd + " -p '" + filterPattern + "'";
        }
        //		List result = new ArrayList();
        List<ResPropertyValue> values = new ArrayList<ResPropertyValue>();
        String[] propMetas = getPropMeta();

        try {
            //			reader = CollectorUtil.getReader(cmd, ip);
            reader = CommandReader.getReader(ip, cmd, (int) this.interval, 0);
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.length() > 0) {
                    int level = this.filter.filter(line);
                    ResPropertyValue propertyValueX = new ResPropertyValue();
                    ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];
                    if (level > 0) {
                        propValues[0] = ResPropertyValue.createPropValue("" + level, propMetas[0]);
                        propValues[1] = ResPropertyValue.createPropValue(line, propMetas[1]);
                        propertyValueX.setValues(propValues);
                        values.add(propertyValueX);
                    }
                }
            }
            return values.size() == 0 ? null : values;
        } catch (IOException e) {
            logger.error("", e);
            return null;
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception ex) {
                }
            }
        }
    }

    private class ORALogFilter {
        private long confLastModified = -1;
        private int defaultLevel = 5;
        private final List<Pattern> nonePatterns = new ArrayList<Pattern>();
        private final Map<Integer, List<Pattern>> levelPatterns = new HashMap<Integer, List<Pattern>>();

        public ORALogFilter() {

        }

        public void init(String confFileName) {
            File file = new File(confFileName);
            if (!file.exists() || file.lastModified() == this.confLastModified) {
                return;
            }
            this.confLastModified = file.lastModified();
            FileInputStream fis = null;
            BufferedReader reader = null;
            try {
                fis = new FileInputStream(file);
                reader = new BufferedReader(new InputStreamReader(fis));
                String line = null;
                int status = -1;
                nonePatterns.clear();
                levelPatterns.clear();
                while ((line = reader.readLine()) != null) {
                    line = line.trim();
                    if (line.equals("") || (line.startsWith("#") && !line.startsWith("#!"))) {
                        continue;
                    }
                    if (line.startsWith("#!default-level:")) {
                        this.defaultLevel = Integer.parseInt(line.substring(16).trim());
                        continue;
                    }
                    if (line.equals("#!filter-code:")) {
                        status = 0;
                        continue;
                    }
                    if (line.startsWith("#!level-")) {
                        status = Integer.parseInt(line.substring(8, line.length() - 1).trim());
                        continue;
                    }
                    if (status < 0) {
                        continue;
                    }
                    if (status == 0) {
                        try {
                            nonePatterns.add(Pattern.compile(line));
                        } catch (Exception ex) {
                        }
                    } else {
                        List<Pattern> list = levelPatterns.get(status);
                        if (list == null) {
                            list = new ArrayList<Pattern>();
                            levelPatterns.put(status, list);
                        }
                        try {
                            list.add(Pattern.compile(line));
                        } catch (Exception ex) {
                        }
                    }
                }
            } catch (Exception e) {

            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                    }
                }
            }
        }

        public int filter(String line) {
            for (int i = 0; i < this.nonePatterns.size(); i++) {
                if (this.nonePatterns.get(i).matcher(line).find()) {
                    return -1;
                }
            }
            for (Iterator ir = this.levelPatterns.keySet().iterator(); ir.hasNext();) {
                Integer level = (Integer) ir.next();
                List<Pattern> list = this.levelPatterns.get(level);
                for (int i = 0; i < list.size(); i++) {
                    if (list.get(i).matcher(line).find()) {
                        return level;
                    }
                }
            }
            return this.defaultLevel;
        }
    }

    //	public static void main(String[] args) {
    //		org.apache.log4j.PropertyConfigurator
    //				.configure("conf/log4j.properties");
    //		SystemLog c = new SystemLog();
    //		ResAttributeValValue[] resourceAttributes = new ResAttributeValValue[2];
    //		resourceAttributes[0] = new ResAttributeValValue();
    //		resourceAttributes[0].setAttrValue("/home/orcl/temp/ora.log");
    //		resourceAttributes[1] = new ResAttributeValValue();
    //		resourceAttributes[1].setAttrValue("tangli.conf");
    //		List list = c.collect(resourceAttributes, "132.194.5.101");
    //		CollectorUtil.dumpCollectResult(list);
    //	}
    private String getFullFileName(String path, String fileName) {
        path = path.trim();
        if (path.endsWith("/")) {
            return path + fileName;
        } else {
            return path + "/" + fileName;
        }
    }

    @Override
    public String[] getParamMeta() {
        return new String[] { "FilePath", "FileName", "FilterCode", "FilterCondition" };
    }

    @Override
    public String[] getPropMeta() {
        return new String[] { "ErrorLevel", "ErrorContent" };
    }
}
